﻿namespace Test
{
    using System;
    using Util;

    class KMeansTester : Test.ITester
    {
        public string Name()
        {
            return "KMeansTester";
        }

        public void Test()
        {
            // ------------------------ 1, 1, 1, 1 ------------------------
            double[] value = new double[] { 1, 1, 1, };
            int numCenters = 1;
            double trueCost = 0;
            VerifyCase(value, numCenters, trueCost);

            value = new double[] { 1, 1, 1, };
            numCenters = 3;
            trueCost = 0;
            VerifyCase(value, numCenters, trueCost);

            value = new double[] { 1, 1, 1, };
            numCenters = 5;
            trueCost = 0;
            VerifyCase(value, numCenters, trueCost);

            // ------------------------ 1, 2, 3, 4 ------------------------
            value = new double[] { 1, 2, 3, 4 };
            numCenters = 1;
            trueCost = 4;
            VerifyCase(value, numCenters, trueCost);

            numCenters = 2;
            trueCost = 2;
            VerifyCase(value, numCenters, trueCost);

            // ------------------------ 1, 1, 3, 4 ------------------------
            value = new double[] { 1, 1, 3, 4 };
            numCenters = 1;
            trueCost = 5;
            VerifyCase(value, numCenters, trueCost);

            numCenters = 2;
            trueCost = 1;
            VerifyCase(value, numCenters, trueCost);

            // -------------------- 1, 1, 3, 4, 4, 7, 100 ---------------------
            value = new double[] { 1, 1, 3, 4, 4, 7, 100 };
            numCenters = 1;
            trueCost = 106;
            VerifyCase(value, numCenters, trueCost);

            numCenters = 2;
            trueCost = 10;
            VerifyCase(value, numCenters, trueCost);

            numCenters = 3;
            trueCost = 4;
            VerifyCase(value, numCenters, trueCost);

            numCenters = 4;
            trueCost = 1;
            VerifyCase(value, numCenters, trueCost);
        }

        private void VerifyCase(double[] value, int numCenters, double trueCost)
        {
            double cost;
            double[] centers = KMeans.KMeansOneDim(value, numCenters, out cost);

            bool res = true;
            if (cost != trueCost)
            {
                res = false;
                Console.WriteLine("Wrong cost returned!");
            }
            if (res)
            {
                Array.Sort(value);
                Array.Sort(centers);
                double total = 0;
                int cur = 0;
                for (int i = 0; i < value.Length; ++i)
                {
                    while (cur + 1 < numCenters && Math.Abs(value[i] - centers[cur + 1]) < Math.Abs(value[i] - centers[cur])) ++cur;
                    total += Math.Abs(value[i] - centers[cur]);
                }
                if (total != cost)
                {
                    res = false;
                    Console.WriteLine("The centers returned don't match the cost returned!");
                }
            }

            if (res)
            {
                Console.WriteLine("Passed...");
            }
            else
            {
                Console.WriteLine("True cost: {0}, cost returned by KMeans.KMeansOneDim: {1}", trueCost, cost);
                Console.WriteLine("Number of centers: " + numCenters);
                Console.Write("Values:");
                Generic.ShowListOnConsole(value);
                Console.Write("Centers returned by KMeans.KMeansOneDim:");
                Generic.ShowListOnConsole(centers);
            }
            Console.WriteLine();
        }
    }
}
